/**
 * Copyright 2008 Mathias Doenitz, http://lis.to/
 *
 * This file is part of the lis.to java desktop client. The lis.to java desktop client is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * The lis.to java desktop client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with the lis.to java desktop client.
 * If not, see http://www.gnu.org/licenses/
 */

package listo.client.dialogs.controllers;

import com.google.inject.Inject;
import listo.client.ContextManager;
import listo.client.Formatter;
import listo.client.Lang;
import listo.utils.swing.AutoCompleter;
import listo.client.dialogs.autocompletion.QuickEntryCompleter;
import listo.client.model.Context;
import listo.client.model.Folder;
import listo.client.model.ObjectId;
import listo.client.model.Task;
import listo.utils.guice.ManuallyScoped;
import listo.utils.types.Cal;
import org.apache.commons.lang.StringUtils;

import javax.swing.*;
import javax.swing.text.JTextComponent;
import java.awt.event.FocusEvent;
import java.text.DateFormat;
import java.util.Set;

@ManuallyScoped("TaskDialogScope")
public class TaskQuickEntryController extends TextComponentController<Task>
        implements ComponentController.ModelChangedListener {

    private final Formatter formatter;
    private final QuickEntryCompleter quickEntryCompleter;
    private final TaskDescController descController;
    private final TaskDueDateController dueDateController;
    private final TaskDueTimeController dueTimeController;
    private final TaskReminderController reminderController;
    private final TaskFoldersController foldersController;
    private final Context currentContext;
    private final DateFormat timeFormat;

    @Inject
    public TaskQuickEntryController(Formatter formatter, QuickEntryCompleter quickEntryCompleter,
                                    TaskDescController descController,
                                    TaskDueDateController dueDateController,
                                    TaskDueTimeController dueTimeController,
                                    TaskReminderController reminderController,
                                    TaskFoldersController foldersController,
                                    ContextManager contextManager, Lang lang) {
        this.formatter = formatter;
        this.quickEntryCompleter = quickEntryCompleter;
        this.descController = descController;
        this.dueDateController = dueDateController;
        this.dueTimeController = dueTimeController;
        this.reminderController = reminderController;
        this.foldersController = foldersController;
        this.currentContext = contextManager.getCurrentContext();
        this.timeFormat = lang.getTimeFormat();

        descController.addModelChangedListener(this);
        addModelChangedListener(descController);
        dueDateController.addModelChangedListener(this);
        addModelChangedListener(dueDateController);
        dueTimeController.addModelChangedListener(this);
        addModelChangedListener(dueTimeController);
        reminderController.addModelChangedListener(this);
        addModelChangedListener(reminderController);
        foldersController.addModelChangedListener(this);
        addModelChangedListener(foldersController);
    }

    public void setDialogComponent(JDialog dialog, JComponent component) {
        super.setDialogComponent(dialog, component);
        new AutoCompleter(quickEntryCompleter).decorate(dialog, (JTextComponent) component);
    }

    protected void updateView(boolean active) {
        StringBuilder sb = new StringBuilder();

        String desc = modelObject.getDesc();
        if (StringUtils.isNotEmpty(desc)) {
            sb.append(desc);
        }

        if (modelObject.hasDueDate()) {
            if (sb.length() > 0) sb.append(' ');
            sb.append('=').append(formatter.toShortDateString(modelObject.getDue()));
        }
        if (modelObject.hasDueTime()) {
            Cal cal = new Cal(modelObject.getDue());
            if (sb.length() > 0) sb.append(' ');
            sb.append(cal.format(timeFormat));
        }

        Integer reminder = modelObject.getReminder();
        if (reminder != null) {
            if (sb.length() > 0) sb.append(' ');
            sb.append(formatter.toShortReminderString(modelObject.getDue(), reminder));
        }

        Set<ObjectId> folderIds = modelObject.getFolders();
        if (folderIds != null) {
            for (ObjectId folderId : folderIds) {
                Folder folder = currentContext.getFolder(folderId);
                sb.append(' ').append('@').append(folder.getPathName());
            }
        }

        setText(sb.toString());
    }

    protected void extractFromString(String string) {
        String[] words = StringUtils.split(string);

        String dueDate = "";
        String dueTime = "";
        String reminder = "";
        StringBuilder desc = new StringBuilder();
        StringBuilder folders = new StringBuilder();

        for (int i = 0; i < words.length; i++) {
            String word = words[i];

            if (word.startsWith("=")) {
                dueDate = word.substring(1);
                if (++i < words.length) {
                    word = words[i];
                    if (word.length() > 0 && Character.isDigit(word.charAt(0))) {
                        dueTime = word;
                        if (++i < words.length) {
                            word = words[i].toLowerCase();
                            if ("am".equals(word) || "pm".equals(word)) {
                                word = ++i < words.length ? words[i] : "";
                            }
                            if (word.startsWith("+") || word.startsWith("-") || "0".equals(word)) {
                                reminder = word;
                            } else {
                                i--;
                            }
                        }
                    } else {
                        i--;
                    }
                }
                continue;
            }
            if (word.startsWith("@")) {
                if (folders.length() > 0) folders.append(", ");
                folders.append(word.substring(1));
                continue;
            }
            if (desc.length() > 0) desc.append(' ');
            desc.append(word);
        }

        descController.extractFromString(desc.toString());
        dueDateController.extractFromString(dueDate);
        dueTimeController.extractFromString(dueTime);
        reminderController.extractFromString(reminder);
        foldersController.extractFromString(folders.toString());
    }

    public boolean isComponentValid() {
        return true;
    }

    public void focusGained(FocusEvent e) {
        super.focusGained(e);
        textComponent.setCaretPosition(0);
        textComponent.moveCaretPosition(StringUtils.length(modelObject.getDesc()));
    }

    public void modelChanged(ComponentController... controllers) {
        if (controllers[0] != this) updateView(false);
    }
}
